import pandas as pd
import numpy as np
from ast import literal_eval
from sklearn.preprocessing import MultiLabelBinarizer

# ======================
# 1. 加载示例数据（替换为实际CSV文件路径）
# ======================
data = pd.read_csv('tourism_dataset.csv')

df = pd.DataFrame(data)

# ======================
# 2. 数据类型转换
# ======================
def safe_convert(obj):
    """安全转换字符串列表为实际列表"""
    try:
        return literal_eval(obj)
    except:
        return []

# 转换列表型字段
list_columns = ['Interests', 'Sites Visited']
for col in list_columns:
    df[col] = df[col].apply(safe_convert)

print("转换后的数据类型：")
print(df.dtypes)

# ======================
# 3. 缺失值处理
# ======================
print("\n缺失值统计：")
print(df.isnull().sum())

# 处理缺失值示例：
# df['Age'].fillna(df['Age'].median(), inplace=True)
# df['Site Name'].fillna("Unknown", inplace=True)
# df.dropna(subset=['Sites Visited'], inplace=True)

# ======================
# 4. 异常值处理
# ======================
# 定义有效范围
VALID_AGE = (18, 100)
VALID_DURATION = (1, 30)

# 处理年龄异常值
age_mask = df['Age'].between(*VALID_AGE)
df.loc[~age_mask, 'Age'] = df['Age'].median()

# 处理旅游时长异常值
duration_mask = df['Tour Duration'].between(*VALID_DURATION)
df = df[duration_mask].copy()

# ======================
# 5. 数据一致性检查
# ======================
# 检查景点名称有效性
VALID_SITES = {
    'Eiffel Tower', 'Great Wall of China',
    'Taj Mahal', 'Machu Picchu', 'Colosseum'
}

# 验证访问景点
df['Valid Sites'] = df['Sites Visited'].apply(
    lambda sites: all(site in VALID_SITES for site in sites)
)

# 标记无效记录
invalid_records = df[~df['Valid Sites']]
print("\n无效景点记录：")
print(invalid_records)

# 修正时长一致性
df['Tour Duration'] = df.apply(
    lambda row: min(row['Tour Duration'], row['Preferred Tour Duration']),
    axis=1
)

# ======================
# 6. 协同过滤准备
# ======================
# 展开访问景点
exploded_df = df.explode('Sites Visited')

# 构建用户-景点交互矩阵
user_item_matrix = pd.pivot_table(
    exploded_df,
    index='Tourist ID',
    columns='Sites Visited',
    values='Tourist Rating',
    aggfunc='count',
    fill_value=0
)

print("\n用户-景点交互矩阵：")
print(user_item_matrix)

# 兴趣特征编码
mlb = MultiLabelBinarizer()
interests_encoded = pd.DataFrame(
    mlb.fit_transform(df['Interests']),
    columns=mlb.classes_,
    index=df.index
)

# 合并最终数据集
final_df = pd.concat([df, interests_encoded], axis=1)

# ======================
# 7. 保存清洗后数据
# ======================
final_df.to_csv("cleaned_tourism_data.csv", index=False)
user_item_matrix.to_csv("user_item_matrix.csv")

print("\n数据清洗完成！清洗后数据已保存为CSV文件。")